package com.ztr.phone;

import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;
public class DataMaskingUtils {
    /**
     * 对字符串进行脱敏处理。
     *
     * @param str 需要脱敏处理的字符串。
     * @param pre 前面保留的字符数。
     * @param suf 后面保留的字符数。
     * @return 返回脱敏后的字符串。
     */
    public static String strMasking(String str, int pre, int suf) {
        // 如果字符串为空或只包含空白字符，直接返回原字符串
        if (StrUtil.isBlank(str)) {
            return str;
        }
        // 如果前后保留的字符数都为0或负数，直接返回原字符串
        if (pre <= 0 && suf <= 0) {
            return str;
        }
        int len = str.length();
        // 如果字符串长度大于预保留和后保留字符数之和，处理并返回脱敏后的字符串
        if (len > (pre + suf)) {
            return StrUtil.subPre(str, pre) +
                    StrUtil.fill("", '*', len - pre - suf, false) +
                    StrUtil.subSufByLength(str, suf);
        // 如果字符串长度大于预保留字符数且预保留字符数大于0，处理并返回脱敏后的字符串
        } else if (len > pre && pre > 0) {
            return StrUtil.subPre(str, pre) +
                    StrUtil.fill("", '*', len - pre, false);
        // 如果字符串长度大于后保留字符数且后保留字符数大于0，处理并返回脱敏后的字符串
        } else if (len > suf && suf > 0) {
            return StrUtil.fill("", '*', len - suf, false) +
                    StrUtil.subSufByLength(str, suf);
        // 如果字符串长度小于等于预保留和后保留字符数中的最大值，全星号处理后返回
        } else {
            return StrUtil.fill("", '*', len, false);
        }
    }

    /**
     * 对给定的全名进行处理，只显示第一个汉字，其余部分用星号隐藏<例如：李**>
     *
     * @param fullName 个人的全名
     * @return 返回处理后的姓名字符串，如果输入为空则返回空字符串
     */
    public static String chineseName(String fullName) {
        // 检查输入的姓名是否为空，如果为空则直接返回空字符串
        if (StringUtils.isBlank(fullName)) {
            return "";
        }
        // 提取并返回姓名中的第一个汉字
        String name = StringUtils.left(fullName, 1);
        // 用星号填充剩余部分，以达到隐藏效果
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     * 根据给定的中文姓名，只显示姓氏，名字部分以星号隐藏。例如：欧阳娜娜 -> 欧阳**
     *
     * @param familyName 姓氏。这部分将被完整显示。
     * @param givenName  名字。这部分将被星号替换。
     * @return 返回处理后的中文姓名，仅显示姓氏，名字用星号代替。
     */
    public static String chineseName(String familyName, String givenName) {
        // 检查输入的姓或名是否为空，若为空则返回空字符串
        if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
            return "";
        }
        // 如果姓氏超过一个字符，保留第一个字符，其余用星号代替
        if (familyName.length() > 1) {
            String name = StringUtils.left(familyName, 1); // 仅保留第一个字符
            return StringUtils.rightPad(name, StringUtils.length(familyName + givenName), "*"); // 用星号填充至与原姓名长度相同
        }
        // 如果姓氏只有一个字符，将姓氏和名字合并后递归调用本函数进行处理
        return chineseName(familyName + givenName);
    }

    /**
     * 隐藏身份证号中间部分，只显示最后四位数字。身份证号可以是18位或15位。
     * 例如，输入为"123456789012345678"，则输出为"*************5678"。
     * 如果输入的身份证号为空或白空，则返回空字符串。
     *
     * @param id 待处理的身份证号字符串。
     * @return 处理后的身份证号字符串，中间部分用"*"隐藏，保留最后四位。
     */
    public static String idCardNum(String id) {
        // 检查输入的字符串是否为空
        if (StringUtils.isBlank(id)) {
            return "";
        }
        // 获取身份证号的最后四位数字
        String num = StringUtils.right(id, 4);
        // 使用"*"字符填充至原身份证号长度，保留最后四位数字
        return StringUtils.leftPad(num, StringUtils.length(id), "*");
    }

    /**
     * 隐藏身份证中间部分数字，只显示前六位和后四位，其它位用星号代替。
     * 例如，输入为4510021234567891647，输出为451002********1647。
     *
     * @param carId 身份证号字符串
     * @return 隐藏后的身份证号字符串。如果输入为空或null，则返回空字符串。
     */
    public static String idCard(String carId) {
        // 检查输入字符串是否为空，如果为空则直接返回空字符串
        if (StringUtils.isBlank(carId)) {
            return "";
        }
        // 返回处理后的身份证号，处理逻辑为取前六位，然后用星号隐藏中间部分，最后加上后四位
        return StringUtils.left(carId, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(carId, 4), StringUtils.length(carId), "*"), "******"));
    }

    /**
     * 隐藏固定电话号码的中间部分，只显示最后四位数字。
     * 通过在电话号码的左侧添加星号("*")来隐藏除最后四位之外的所有数字。
     * 如果输入的电话号码为空或不包含数字，则返回空字符串。
     * 例子：输入 "02112345678"，返回 "***1234"。
     *
     * @param num 待处理的固定电话号码字符串。
     * @return 处理后的电话号码字符串，其中中间部分被星号隐藏，只显示最后四位。
     */
    public static String fixedPhone(String num) {
        // 检查输入的电话号码是否为空或只包含非数字字符
        if (StringUtils.isBlank(num)) {
            return "";
        }
        // 从右往左取最后四位数字，并使用leftPad方法在左侧填充星号，以保留原号码长度
        return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
    }

    /**
     * 隐藏手机号码中间的数字，只显示前三位和后四位，其他位数用星号(*)代替。
     * 例如，手机号码13812345678会被处理为138******5678。
     *
     * @param num 待处理的手机号码字符串。
     * @return 处理后的手机号码字符串，如果输入为空则返回空字符串。
     */
    public static String mobilePhone(String num) {
        // 检查输入的手机号是否为空
        if (StringUtils.isBlank(num)) {
            return "";
        }
        // 将手机号码的前三位与用星号代替的后四位拼接起来，中间的数字被隐藏
        return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), "***"));
    }

    /**
     * 对给定的地址信息进行脱敏处理，只显示到地区级别，隐藏详细地址，以增强个人信息保护。
     * 例如，将"北京市海淀区中关村大街1号"处理成"北京市海淀区****"。
     *
     * @param address 需要进行脱敏处理的地址字符串。
     * @param sensitiveSize 需要隐藏的敏感信息的长度。
     * @return 返回脱敏处理后的地址字符串。如果输入的地址为空或null，则返回空字符串。
     */
    public static String address(String address, int sensitiveSize) {
        // 判断地址是否为空，如果为空则直接返回空字符串
        if (StringUtils.isBlank(address)) {
            return "";
        }
        int length = StringUtils.length(address); // 获取地址字符串的长度
        // 使用rightPad将地址的后sensitiveSize个字符替换为"*"，并返回处理后的字符串
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
    }

    /**
     * 隐藏电子邮箱的中间部分，只显示第一个字符，其余用星号代替，但保留@及后面的域名部分。
     * 例如，g**@163.com。
     *
     * @param email 需要进行隐藏处理的电子邮箱字符串。
     * @return 返回处理后的电子邮箱字符串。如果输入为空或不包含@符号，则返回原字符串。
     */
    public static String email(String email) {
        // 检查输入的邮件地址是否为空
        if (StringUtils.isBlank(email)) {
            return "";
        }

        // 查找@符号的位置
        int index = StringUtils.indexOf(email, "@");
        // 如果@符号在第一个字符之后的位置，进行隐藏处理
        if (index <= 1) {
            return email;
        }

        // 将邮件地址的前缀部分用星号隐藏并拼接@及后面的域名部分
        return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
    }

    /**
     * 银行卡号脱敏处理方法
     * 前六位，后四位，其他用星号隐藏（每位1个星号）。例如：6222600**********1234
     *
     * @param cardNum 需要处理的银行卡号字符串
     * @return 经过脱敏处理的银行卡号字符串。如果输入为空或null，则返回空字符串。
     */
    public static String bankCard(String cardNum) {
        // 检查输入字符串是否为空，如果为空则直接返回空字符串
        if (StringUtils.isBlank(cardNum)) {
            return "";
        }
        // 将银行卡号前六位与后四位连接，中间用星号隐藏。首先取出前六位，然后从后往前取四位，并在两者之间用星号填充。
        return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
    }

    /**
     * 对公司开户银行联行号进行处理，只显示前两位，其余位数用星号隐藏。
     * 例如，输入为 "1234567890"，则输出为 "12********"。
     *
     * @param code 公司开户银行联行号，字符串类型。
     * @return 处理后的银行联行号字符串，如果输入为空或null，则返回空字符串。
     */
    public static String cnapsCode(String code) {
        // 检查输入字符串是否为空，如果为空则直接返回空字符串
        if (StringUtils.isBlank(code)) {
            return "";
        }
        // 使用StringUtils的rightPad和left方法，将输入字符串的前两位与星号组合起来，
        // 以达到隐藏除前两位外的其他信息的目的
        return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");
    }


}
